package client;

import lovedna.game.materials.RenderQueue;
import lovedna.Debug;
import lovedna.graphics.CullMode;
import lovedna.game.materials.Material;
import lovedna.utils.macro.CompileTime;
import lovedna.game.materials.ShaderSource;
import lovedna.game.GameTime;
import lovedna.game.Mesh;
import lovedna.game.components.MeshRenderer;
import lovedna.math.Quaternion;
import lovedna.math.Vector3;
import haxe.ds.StringMap;
import lovedna.format.animation.AnimationClip;
import lovedna.events.Event;
import lovedna.resource.R;
import common.table.data.TableDataActor;
import lovedna.game.helper.EnvSampler;
import lovedna.game.components.Gltf;
import lovedna.game.Actor;

class Animal extends Actor {
	private static inline var state_loading:Int = 0;
	private static inline var state_born:Int = 1;
	private static inline var state_idle:Int = 2;
	private static inline var state_walk:Int = 3;
	private static inline var state_run:Int = 4;
	private static inline var state_click:Int = 5;
	private static inline  var g:Float=10;
	public var actorData(default,null):TableDataActor;
	public var x:Int;
	public var y:Int;
	public var forwardX:Int;
	public var forwardY:Int;
	public var forwardHeight:Int;
	private var _fallT:Float;
	public var moving:Bool;
	private var _gltf:Gltf;
	private var _state:Int;
	private var _stateTime:Float;
	private var _idleTime:Float;
	private var _moveFrom:Vector3;
	private var _moveTarget:Vector3;

	private var _rotationTarget:Quaternion;

	private static var _loopSet:StringMap<Int>;

	private var _aniState:StringMap<AnimationClip>;

	private var _body:Actor;
	private var _selected:Bool;

    public function new() {
        super();
		
		_stateTime = 0;
		_idleTime = 0;
		_body = new Actor();
		_body.setParent(this);
		_body.transform.scale.set(100, 100, 100);
		_body.transform.rotation.setEulerAngles(0,180,0);
		_gltf = _body.addComponent(Gltf);
		_gltf.env = new EnvSampler();
		_gltf.addEventListener(Event.init.type, gltfinit);
		_gltf.onRendererCreate = renderer -> {
			for (m in renderer.materials) {
				m.renderState.depthState.writeEnabled = true;
				m.renderState.depthState.setDepthTest(true);
				m.loadShader("animal");
			}
		}
		_state = state_loading;
		_aniState = new StringMap<AnimationClip>();
		if (_loopSet == null) {
			_loopSet = new StringMap<Int>();
			_loopSet.set("Bounce", 1);
			_loopSet.set("Idle_A", -1);
			_loopSet.set("Walk", -1);
			_loopSet.set("Run", -1);
			_loopSet.set("Clicked", 1);
		}
		_moveFrom=new Vector3();
		_moveTarget = new Vector3();
		_rotationTarget = new Quaternion();
    }
	public function config(table:TableDataActor) {
		actorData = table;
		_gltf.resource = R.gltf.getRes("models/" + actorData.stringValue);
		_body.transform.position.fromArray(actorData.offset);
		_rotationTarget.setEulerAngles(0,table.rotation,0);
		transform.rotation.copy(_rotationTarget);
		_selected=false;
	}
	public function load() {
		moving=false;
		forwardX=forwardY=forwardHeight=0;
	}
	public function canMove() {
		var b=forwardX!=0 || forwardY!=0;
		if(!b){
			moving=false;
		}
		return b;
	}
	public function stopMove() {
		forwardX=forwardY=forwardHeight=0;
		moving=false;
	}
	private var _moveFinish:Animal->Void;
	private var _moveProgress:Float;
	public function moveTo(px:Float,py:Float,finish:Animal->Void) {
		if(moving)return;
		_moveFinish=finish;
		moving=true;
		_moveFrom.copy(transform.position);
		_moveTarget.set(px,0,py);
		setState(state_walk);
		_moveProgress=0;
		if(forwardHeight>0){
			_fallT=Math.sqrt(forwardHeight*2/g)*2;
		}
	}

	private function gltfinit(?e) {
		for (k => v in _loopSet) {
			var ani = _gltf.resource.data.getAnimation(k);
			if (ani == null)
				continue;
			_aniState.set(k, new AnimationClip(ani.animation, 0, -1, v));
		}
		setState(state_born);
	}
	public function select(value:Bool) {
		if(_selected==value){
			return;
		}
		var len=_gltf.rendererCount;
		while (len-- > 0){
			var r = _gltf.getRenderer(len);
			r.actor.layer=value?10:0;
			// r.materialCount=value?2:1;
		}
		_selected=value;	
	}
	public function setRotation(dir:Vector3,flush:Bool=false) {
		_rotationTarget.setLookAt(dir.normalize());
		if(flush){
			this.transform.rotation.copy(_rotationTarget);
		}
	}
	public function setState(value:Int) {
		if (_state == value)
			return;
		_state = value;
		_idleTime = 0;
		var clipName:String = null;
		var clip:AnimationClip = null;
		if (_state == state_born) {
			clipName = "Bounce";
		} else if (_state == state_idle) {
			clipName = "Idle_A";
		} else if (_state == state_walk) {
			clipName = "Walk";
		} else if (_state == state_run) {
			clipName = "Run";
		} else if (_state == state_click) {
			clipName = "Clicked";
		}
		clip = _aniState.get(clipName);
		if (clip == null)
			return;
		_gltf.setBoneAnimation(clip, 0.1);
		if (_loopSet.get(clipName) == 1) {
			_stateTime = clip.totalTime;
		} else {
			_stateTime = 0;
		}
	}

	override function onUpdate() {
		if (_state == state_loading)
			return;
		if (_stateTime > 0) {
			_stateTime -= deltaTime;
			if (_stateTime <= 0) {
				nextAction();
			}
		}
		this.transform.rotation.slerpTo(_rotationTarget, GameTime.deltaTime * 20);
		// return;
		if (_state == state_born) {

        } else if (_state == state_idle) {
			
		} else if (_state == state_walk || _state==state_run) {
			_moveProgress += deltaTime*4;
			if (_moveProgress<1){
				this.transform.position.copy(_moveFrom).lerpTo(_moveTarget,_moveProgress);
				if(forwardHeight>0){
					var t=_fallT*_moveProgress;
					var ht=_fallT*0.5;
					var vt=g*ht;
					var v0=vt;
					var h=v0*t-0.5*g*t*t;
					this.transform.position.y=h;
				}
				
			}else
			{
				this.transform.position.copy(_moveTarget);
				setState(state_idle);
				moving=false;
				
				if (_moveFinish != null) {
					var callback=_moveFinish;
					_moveFinish = null;
					callback(this);
				}else
				{
					trace("not find callback");
				}
			}
		} else if (_state == state_run) {

		} else if (_state == state_click) {
			
		}
	}
	
	private function nextAction() {
		if (_state == state_born) {
			setState(state_idle);
		} else if (_state == state_idle) {}
	}

}
